﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Practices.Unity;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Input;
using Microsoft.Surface.Presentation.Palettes;
using ScrumTable.Config.ConfigManagement;
using ScrumTable.Config.ElementManagement;
using ScrumTable.Config.UserManagement;
using ScrumTable.Common;
using ScrumTable.Common.Logging;
using ScrumTable.Common.SysLibs;
using ScrumTable.Common.Threading;
using ScrumTable.UI.View.Localization;
using ScrumTable.UI.View.Util;
using ScrumTable.UI.View.WinTouch.Util;
using ScrumTable.UI.ViewModel.Controller;
using ScrumTable.UI.ViewModel.Data;
using ScrumTable.UI.ViewModel.Tools.Toast;

namespace ScrumTable.UI.View.WinTouch
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private IUnityContainer _container;

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Initializes a new instance of the <see cref="App"/> class.
        /// </summary>
        /// <exception cref="T:System.InvalidOperationException">
        /// More than one instance of the <see cref="T:System.Windows.Application"/> class is created per <see cref="T:System.AppDomain"/>.
        /// </exception>
        public App()
        {
            DispatcherUnhandledException += OnDispatcherUnhandledException;
        }

        
        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        private void InitializeLogging()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeLogging,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeLoggingCompleted,
                () =>
                {
                    LoggerConfig.RegisterConfigFile("Logging/LoggingConfig.xml");
                });
        }

        private void InitializeLanguage()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeLanguage,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeLanguageCompleted,
                ScrumTableLanguage.RegisterDefaultDictionaries);
        }

        /// <remarks>
        /// Error:  Object synchronization method was called from an unsynchronized block of code
        /// Answer: By design. This exception is expected, caught, and handled internally. It only shows up in the debugger and does not affect the execution at all.
        /// </remarks>
        private void InitializeDiContainer(string[] args)
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeDiContainer,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeDiContainerCompleted,
                () =>
                {
                    _container = new UnityContainer();
                    _container.RegisterInstance<IUnityContainer>(_container);
                });
        }

        private void InitializeUserManager()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeUserManager,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeUserManagerCompleted,
                () =>
                {
                    _container.RegisterInstance(LoginAccountManagerFactory.CreateUserManager());
                });
        }

        private void InitializeConfigManager()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeConfigManager,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeConfigManagerCompleted,
                () =>
                    {
                        ConfigManager manager = ConfigManagerFactory.CreateConfigManager();
                        _container.RegisterInstance(manager);
                        LanguageContext.Instance.CultureString = manager.CultureInfo;
                    });
        }


        private void InitializeElementManager()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeElementManager,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeElementManagerCompleted,
                () =>
                {
                    ElementManager manager = ElementManagerFactory.CreateConfigManager();
                    _container.RegisterInstance(manager);
                });
        }


        private void InitializeViewModel()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeViewModel,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeViewModelCompleted,
                () =>
                {
                    _container.RegisterInstance<ScrumViewModelData>(_container.Resolve<ScrumViewModelData>());
                });
        }

        private void InitializeToastViewModel()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeToastViewModel,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeToastViewModelCompleted,
                () =>
                {
                    _container.RegisterInstance<ViewModelToastScreen>(_container.Resolve<ViewModelToastScreen>());
                });
        }

        private void InitializeUiController()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeUiController,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeUiControllerCompleted,
                () =>
                {
                    _container.RegisterInstance(_container.Resolve<ScrumController>());
                });
        }

        private void InitializeStartScreen()
        {
            Logger<App>.SurroundInfo(
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeStartScreen,
                ScrumTable.UI.View.WinTouch.Properties.Resources.LogInitializeStartScreenCompleted,
                () =>
                {
                    AppScreen screen = _container.Resolve<AppScreen>();
                    screen.Closed += OnScreenClosed;
                    _container.RegisterInstance(screen);
                    _container.RegisterInstance(typeof(IRunTaskWithGuiSupplie), screen);
                    Current.MainWindow = screen;
                    screen.Show();
                    _container.RegisterInstance<IDataSyncDispatcher>(new SyncDispatcher(screen.Dispatcher));
#if SimulatorDebug
                    //Log In in Debug-Mode
                    _container.Resolve<LoginAccountManager>().SetCurrentLoginAccount(2);
                    _container.Resolve<ScrumViewModelData>().Connect("test", NavigationTarget.Null, true, null);
#endif
                });
        }

        private void InitializeRessources() 
        {
            foreach (var res in Resources)
            {
                if (res is DictionaryEntry && ((DictionaryEntry)res).Value is Brush)
                {
                    if (((Brush)((DictionaryEntry)res).Value).CanFreeze)
                    {
                        ((Brush)((DictionaryEntry)res).Value).Freeze();
                    }
                }
            }
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        protected override void OnStartup(StartupEventArgs eventArgs)
        {
            
                InitializeRessources();
                InitializeLogging();
                
                Logger<App>.SurroundInfo(
                    string.Format(WinTouch.Properties.Resources.LogStartUp,Assembly.GetExecutingAssembly().GetName().Version),
                    string.Format(WinTouch.Properties.Resources.LogStartUpCompleted, Assembly.GetExecutingAssembly().GetName().Version),
                    () =>
                        {
                            InitializeLanguage();
                            base.OnStartup(eventArgs);
                            InitializeDiContainer(eventArgs.Args);
                            InitializeUserManager();
                            InitializeConfigManager();
                            InitializeElementManager();
                            InitializeUiController();
                            InitializeViewModel();
                            InitializeToastViewModel();
                            InitializeStartScreen();
                        });
 

        }



        private void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            Logger<App>.ErrorFormat(ScrumTable.UI.View.WinTouch.Properties.Resources.LogProgramCrash);

            if (e != null && e.Exception != null)
            {
                Logger<App>.Fatal(e.Exception.ToFullErrorString());
            }
            else
            {
                Logger<App>.Fatal(ScrumTable.UI.View.WinTouch.Properties.Resources.LogProgramCrashNoException);
            }

#if DEBUG
            System.Diagnostics.Debugger.Launch();
#endif
            try
            {
                var fileInfo = new FileInfo(Application.ResourceAssembly.Location).Directory.FullName + @"\ScrumTableErrorReporter.exe";
                if (File.Exists(fileInfo))
                {
                    Process.Start(fileInfo, (e != null && e.Exception != null) ? "\"" + e.Exception.Message + "\"" : string.Empty);
                }

            }
            catch (Exception restartExc)
            {
                Logger<App>.FatalFormat(ScrumTable.UI.View.WinTouch.Properties.Resources.LogProgramRestartFailed,
                                        restartExc.ToFullErrorString());
            }

            Application.Current.Shutdown();
            e.Handled = true;

        }

        private void OnScreenClosed(object sender, EventArgs e)
        {
            Logger<App>.Debug(ScrumTable.UI.View.WinTouch.Properties.Resources.LogProgramClosed);

            ((AppScreen)sender).Closed -= OnScreenClosed;

            _container.Resolve<LoginAccountManager>().SaveLogin();
            _container.Resolve<ConfigManager>().Save();
            _container.Resolve<ElementManager>().Save();

            Shutdown();
        }
    
        private void OnTouchDown(object sender, TouchEventArgs e)
        {
            Control control = ((Control)sender);
            if (e.Device.Capture(control))
            {
                control.Focus();
                Keyboard.Focus(control);
                e.Handled = true;

                try
                {
                    var point = control.PointToScreen(e.GetTouchPoint(control).Position);
                    System.Windows.Forms.Cursor.Position = new System.Drawing.Point((int)point.X, (int)point.Y);
                    User32Util.SendMessage(new System.Windows.Interop.WindowInteropHelper(Application.Current.MainWindow).Handle, User32Util.WM_LBUTTONDOWN, 0, 0);
                }
                finally
                {
                    e.Device.Capture(null);
                }
            }
        }

        private void OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            
            Control control = (Control) sender;
            if (sender is TextBox)
            {
                
                ((TextBox)control).SelectionStart = 0;
                ((TextBox)control).SelectionLength = 0;
            }
            
            control.Focus();
            Keyboard.Focus(control);

        }


       
        private void OnGotFocus(object sender, RoutedEventArgs e)
        {
            if(_container.Resolve<ConfigManager>().OnboardKeyboardEnabled)
            {
                try
                {
                    KeyboardUtil.StartKeyBoard(sender as FrameworkElement);
                    e.Handled = true;
                }
                catch (Exception ex)
                {
                    Logger<App>.Warn(sender,ex);
                }
            }
        }


        #endregion
    }
}
